#include <asm-generic/ioctls.h>
#include <bits/stdint-intn.h>
#include <bits/stdint-uintn.h>
#include <fcntl.h>
#include <stdint.h>
#include "mg_typedef.h"
#include "message_loop/message_loop.h"
#include "linux/mg_typedef_linux.h"
#if defined( __linux__ )
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#elif defined( __VXWORKS__ )
#endif

/**
 * @brief for Depth Meter
 *
 */
static const uint16_t OUTSIDE_CTD422_NodeID = 0x7110;
#if defined( __linux__ )
static const char OUTSIDE_CTD422_DEVICENAME[] = "/dev/loop1";
#elif defined( __VXWORKS__ )
static const char OUTSIDE_CTD422_DEVICENAME[] = "/tyCo/0";
#endif

static struct CTD422Attr {
  int32_t            fd_;

  int8_t             is_inited_;
  struct sockaddr_in sock_addr_;
  struct ev_loop*    loop_;
} gCTD422Attr;
/**
 * @brief $T=XXX.XXXX ,   P=XXX.XXX ,   C=XX.XXXX ;<回车><换行>
 *      $T=-XXX.XXXX,    P=-XXXX.XXXX,    C=-XX.XXXX\t\n
 * @param w
 * @param revents
 */
static void readMessageHandler( EV_P_ ev_io* w, int revents ) {
  int32_t length               = 0;
  int32_t num_of_bytes_to_read = 0;
  int32_t num_of_bytes_read    = 0;
  char    buf[64];

  length = ioctl( w->fd, FIONREAD, &num_of_bytes_to_read );
  if ( length < 0 ) {
    MG_DEBUG( "Failed to get number-of-data, errno=%d\n", errnoGet( ) );
  }

  length = read( w->fd, &buf, sizeof( buf ) );
  if ( length <= 0 ) {
    MG_DEBUG( "recved no data length=%d,errno=%d\n", length, errnoGet( ) );
    return;
  }
  char* ptr = buf;
  for ( ;; ++ptr ) {
    if ( *ptr == '\0' || *ptr == '\r' || *ptr == '\n' ) {
      break;
    }
  }

  MG_DEBUG( "recved data length=%d,buf[%s]\n", length, buf );
}
/** */
static int32_t serialPortInit( const char*        serialPort,
                               struct CTD422Attr* attr ) {
  int32_t fdCtrlr = 0;
  int32_t status  = -1;
  fdCtrlr         = open( serialPort, O_RDWR, 0 );
  if ( fdCtrlr == ERROR ) {
    MG_DEBUG( "%s,can't open, errno=%d\n", serialPort, errnoGet( ) );
    return -1;
  }
  attr->fd_ = fdCtrlr;
  //
  status = ioctl( fdCtrlr, FIOBAUDRATE, 115200 );
  if ( status < 0 ) {
    MG_DEBUG( "set baudrate failed, ret = %d, set SIO_HW_OPTS_SET failed.\n",
              errnoGet( ) );
  }
  status = ioctl( fdCtrlr, FIOSETOPTIONS, OPT_LINE );
  if ( status < 0 ) {
    MG_DEBUG( "set baudrate failed, ret = %d, set SIO_HW_OPTS_SET failed.\n",
              errnoGet( ) );
  }
  /**
   * @brief 设定：数据位为8，无奇偶校验，1位停止位
   * CLOCAL: 忽略modem控制信号
   * CREAD：启动接收器
   * CS8: 设定数据位为8
   *
   */
  if ( ( status = ioctl( fdCtrlr, SIO_HW_OPTS_SET, CREAD | CS8 | CLOCAL ) )
       < 0 ) {
    MG_DEBUG( "ret = %d, set SIO_HW_OPTS_SET failed.\n", errnoGet( ) );
    //  return -1;
  }
  {
    static ev_io    io_read_watcher;
    struct ev_loop* loop = ev_default_loop( 0 );
    ev_io_init( &io_read_watcher, readMessageHandler, fdCtrlr, EV_READ );
    ev_io_start( loop, &io_read_watcher );
  }
  return 0;
}
static int32_t serialPortClose( const char*        serialPort,
                                struct CTD422Attr* attr ) {
  int32_t ret = -1;
  int32_t st  = -1;
  /* wait until the transmit queue is empty */
  do {
    ret = ioctl( attr->fd_, FIONWRITE, ( int )&st );
    if ( ret != OK ) {
      break;
    }
    if ( st != 0 ) {
      break;
    }
    taskDelay( 5 );
  } while ( 1 );
  if ( attr->fd_ >= 1 ) {
    close( attr->fd_ );
    attr->fd_ = -1;
  }
  return 0;
}
void aCTD422Init( ) {
  serialPortInit( OUTSIDE_CTD422_DEVICENAME, &gCTD422Attr );
}
void aCTD422Close( ) {
  serialPortClose( OUTSIDE_CTD422_DEVICENAME, &gCTD422Attr );
}
int32_t aCTD422Send( const uint8_t* txdata, const int32_t length ) {
  int32_t ret = -1;
  ret         = write( gCTD422Attr.fd_, ( char* )txdata, length );
  if ( ret < length ) {
    //  TODO(kuoted): we should retry later ??????
    MG_DEBUG( "Send failed ret=%d, length=%d", ret, length );
  }
  return ret;
}